package Components;

import Communication.MyTelnet;
import Configuration.configuration;
import DEC.DEC;
import Patterns.SymmetrixComponent;
import java.util.logging.Level;
import org.apache.commons.validator.routines.InetAddressValidator;

/**
 *
 * @author mgrutman
 * @author palugs
 */
public class IBSwitch extends SymmetrixComponent {

    /**
     * Telnet session to the switch
     */
    MyTelnet telnet = new MyTelnet();
    /**
     * IP address of the switch.
     */
    String serverIP;
    /**
     * Password to the switch
     */
    String password;
    /**
     * port at which we telnet. Set to 23 by default.
     */
    int serverPort;
    /**
     * Total number of engines in this machine.
     */
    int numEngines = 4;
    final int numPorts = 36;
    int[][] fourEngineAssignment = {
        {0, 1, 2, 3},
        {0, 0, 1, 1},
        {0, 0, 0, 1},
        {0, 0, 0, 0}
    };
    static final int[][] engineAssignment = {
        {0, 1, 2, 3, 4, 5, 6, 7},
        {0, 0, 1, 1, 2, 2, 3, 3},
        {0, 0, 0, 1, 1, 1, 3, 3},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 1, 1, 2, 2, 3, 4},
        {0, 0, 1, 1, 2, 3, 4, 5},
        {0, 0, 1, 2, 3, 4, 5, 6},
        {0, 0, 0, 1, 2, 3, 4, 5},
        {0, 0, 0, 1, 1, 2, 3, 4},
        {0, 0, 0, 1, 1, 1, 3, 4},
        {0, 0, 0, 1, 1, 1, 3, 3},
        {0, 0, 0, 1, 1, 2, 2, 3},
        {0, 0, 0, 0, 1, 2, 3, 4},
        {0, 0, 0, 0, 1, 1, 1, 2},
        {0, 0, 0, 0, 1, 1, 2, 3},
        {0, 0, 0, 0, 1, 1, 2, 2},
        {0, 0, 0, 0, 1, 1, 1, 1}
    };
    int[] customEngineAssignment;
    configuration choosenConf = configuration.AllSingleEngine;

    public configuration getChoosenConf() {
        return choosenConf;
    }

    public void setChoosenConf(configuration choosenConf) {
        this.choosenConf = choosenConf;
    }

    /**
     *
     * @param ip
     */
    public IBSwitch(String ip, int port, String password) {
        super(IBSwitch.class);
        serverIP = InetAddressValidator.getInstance().isValidInet4Address(ip) ? ip : "192.168.176.190";
        password = "UPOD";
        serverPort = 23;
    }

    @Override
    public boolean connect() {
        l.info("Telnet to " + serverIP + " at port-" + serverPort);
        connected = telnet.initializeCommunicationTo(serverIP, serverPort);
        return connected;
    }

    @Override
    public boolean disconnect() {
        connected = !(telnet.disconnect());
        return !connected;
    }

    public static void process(int numEngines,boolean interactive) 
    {
        IBSwitch[] ibs = new IBSwitch[2];
        
        if(interactive)
        {
            System.out.println("Please enter IP of IBSwitch : ");
            String ip = DEC.readInput();
            if (InetAddressValidator.getInstance().isValid(ip)) 
            {
                ibs[0] = new IBSwitch(ip, 23, "UPOD");
            }
        }
        else
        {
            ibs[0] = new IBSwitch("192.168.176.190", 23, "UPOD");
            ibs[1] = new IBSwitch("192.168.177.191",23, "UPOD");
        }
       
        TheSystem.register(ibs[0]);
        
        for(IBSwitch ib: ibs)
        {
            if (ib.ping()) 
            {
                ib.l.info("IBSwitch at "+ ib.serverIP + "alive.");
                ib.configure();
                ib.disconnect();
            }
            else
            {
                ib.l.info("IBSwitch at "+ ib.serverIP + "is not responding.\nMoving on.");
            }
        }
    }

    public String partitionEngines(int engineAssignment[]) 
    {
        if (engineAssignment.length == 4 || engineAssignment.length == 8) {
            StringBuilder command = new StringBuilder();

            command.append("baz partition engine " + password);

            for (int systemNumber : engineAssignment) 
            {
                command.append(" " + systemNumber);
            }
            return command.toString();
        } 
        else 
        {
            return "";
        }
    }

    public String partitionSwitches(int[] switchAssignment) {
        if (switchAssignment.length == 4 || switchAssignment.length == 8) {
            StringBuilder command = new StringBuilder();

            command.append("baz partition swid");

            for (int partitionToSwitch : switchAssignment) {
                command.append(" " + partitionToSwitch);
            }

            return command.toString();
        } else {
            return "";
        }
    }

    public String partitionPorts(int[] portAssignment) {
        if (portAssignment.length == 36) {
            StringBuilder command = new StringBuilder();

            command.append("baz partition port");

            for (int portToPartition : portAssignment) {
                command.append(" " + portToPartition);
            }

            return command.toString();
        } else {
            return "";
        }
    }

    public String[] CreateCommandsConfiguration() {
        String[] commands = new String[3];
        int[] portAssignment = new int[36];
        int divisionFactor = Math.round(numPorts / numEngines);

        if (numEngines == 4) {
            for (int i = 0; i < numPorts; i++) {
                portAssignment[i] = fourEngineAssignment[choosenConf.hashCode()][i / divisionFactor];
            }

            commands[0] = partitionEngines(fourEngineAssignment[choosenConf.hashCode()]);
            commands[1] = partitionSwitches(fourEngineAssignment[choosenConf.hashCode()]);
            commands[2] = partitionPorts(portAssignment);
        }

        if (numEngines == 8) {

            for (int i = 0; i < numPorts; i++) {
                portAssignment[i] = engineAssignment[choosenConf.hashCode()][i / divisionFactor];
            }
            commands[0] = partitionEngines(engineAssignment[choosenConf.hashCode()]);
            commands[1] = partitionSwitches(engineAssignment[choosenConf.hashCode()]);
            commands[2] = partitionPorts(portAssignment);
        }

        return commands;
    }

    @Override
    public void configure() {
        try {
            l.info("\nConnecting to IBSwitch.");

            if (!connected) {
                connect();
            }

            if (isConnected()) {
                l.info("\nTrying to configure IBSwitch.");

                Thread.sleep(2000);

                l.info(telnet.readAvailable());
            }

            String[] commands = CreateCommandsConfiguration();

            for (String command : commands) {
                l.info(command);
            }

            l.info(".............end of ibswitch configuration..............");

            telnet.disconnect();
        } catch (Exception ex) {
        }
    }

    @Override
    public boolean ping() {
        try {
            int result1 = telnet.myPing(serverIP, 0);

            if (result1 > 0) {
                l.info("Able to ping switch at " + serverIP);
            }

            return (result1 > 0) ? true : false;
        } catch (Exception ex) {
            l.info("Exception communicating with IBSwitch at " + serverIP);
            l.info(ex.getMessage());
        }
        return false;
    }

    @Override
    public void reboot() {
        String[] command = {"restart"};

        telnet.runTelnetCommands(command);
    }
}